#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <grass/G3d.h>

/*---------------------------------------------------------------------------*/


/*!
 * \brief 
 *
 *  Makes a copy of <em>map</em> with name <em>nameOut</em> which is
 *  written with <em>precision</em>.
 * The source code can be found in <em>changeprecision.c</em>.
 *
 *  \param map
 *  \param precision
 *  \param nameOut
 *  \return void
 */

void
G3d_changePrecision  (void *map, int precision, const char *nameOut)

{
  void *map2;
  int x, y, z, savePrecision, saveCompression, saveLzw, saveRle;
  char *data;
  G3D_Region region;
  int typeIntern;
  int nx, ny, nz;
  int tileXsave, tileYsave, tileZsave, tileX, tileY, tileZ, saveType;

  saveType = G3d_getFileType ();
/*   G3d_setFileType (G3d_fileTypeMap (map)); */
  G3d_getCompressionMode (&saveCompression, &saveLzw, &saveRle, 
			  &savePrecision);
  G3d_setCompressionMode (G3D_COMPRESSION, saveLzw, saveRle, precision);
  G3d_getTileDimension (&tileXsave, &tileYsave, &tileZsave);
  G3d_getTileDimensionsMap (map, &tileX, &tileY, &tileZ);
  G3d_setTileDimension (tileX, tileY, tileZ);

  typeIntern = G3d_tileTypeMap (map);
  G3d_getRegionStructMap (map, &region);

  map2 = G3d_openCellNew (nameOut, typeIntern, G3D_USE_CACHE_DEFAULT, &region);
  if (map2 == NULL) 
    G3d_fatalError ("G3d_changePrecision: error in G3d_openCellNew");

  G3d_setFileType (saveType);
  G3d_setCompressionMode (saveCompression, saveLzw, saveRle, savePrecision);
  G3d_setTileDimension (tileXsave, tileYsave, tileZsave);

  data = G3d_allocTiles (map, 1);
  if (data == NULL)
    G3d_fatalError ("G3d_changePrecision: error in G3d_allocTiles");
  G3d_getNofTilesMap (map2, &nx, &ny, &nz);

  for (z = 0; z < nz; z++) 
    for (y = 0; y < ny; y++)
      for (x = 0; x < nx; x++) {
	if (! G3d_readTile (map, G3d_tile2tileIndex (map, x, y, z), data, 
		      typeIntern))
	  G3d_fatalError ("G3d_changePrecision: error in G3d_readTile");
	if (! G3d_writeTile (map2, G3d_tile2tileIndex (map2, x, y, z), data,
			     typeIntern))
	  G3d_fatalError ("G3d_changePrecision: error in G3d_writeTile");
      }

  G3d_freeTiles (data);
  if (! G3d_closeCell (map2)) 
    G3d_fatalError ("G3d_changePrecision: error in G3d_closeCell");
}
